// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __SUB_DEVICE_H__
#define __SUB_DEVICE_H__

#include <time.h>
#include "mdf_common.h"
#include "mlink_json.h"
#include "mlink_utils.h"
#include "mlink_subdevice.h"

#ifdef __cplusplus
extern "C" {
#endif /**< _cplusplus */


#define CONST_STR_NONE "NONE"
#define CONST_STR_DLT645_07 "DLT645-07"
#define CONST_STR_DLT645_97 "DLT645-97"
#define CONST_STR_CJT188_04 "CJT188-04"
#define CONST_STR_MODBUSRTU "ModbusRTU"
#define CONST_STR_MODBUSTCP "ModbusTCP"
#define CONST_STR_MODBUSASCII "ModbusASCII"
#define CONST_STR_MODBUSUDP "ModbusUDP"

#define CONST_STR_FORMAT_U8 "u8"
#define CONST_STR_FORMAT_I8 "i8"
#define CONST_STR_FORMAT_U16 "u16"
#define CONST_STR_FORMAT_I16 "i16"
#define CONST_STR_FORMAT_U32 "u32"
#define CONST_STR_FORMAT_I32 "i32"
#define CONST_STR_FORMAT_FLOAT "float"
#define CONST_STR_FORMAT_STRING "string"
#define CONST_STR_FORMAT_ARRAY "array"

#define SUBDEV_PORT_MAX_NUM 10
#define SUBDEV_CID_MAX_LEN 32
#define SUBDEV_TYPE_MAX_LEN 8

/**
 * @brief Permissions for the subdev_cid
 */
typedef enum {
    SUBDEV_CID_PERMS_READ    = 1 << 0, /**< The subdev_cid of the device are readable */
    SUBDEV_CID_PERMS_WRITE   = 1 << 1, /**< The subdev_cid of the device are writable*/
    SUBDEV_CID_PERMS_TRIGGER = 1 << 2, /**< The subdev_cid of the device can be triggered */
    SUBDEV_CID_PERMS_RW      = SUBDEV_CID_PERMS_READ | SUBDEV_CID_PERMS_WRITE,    /**< The subdev_cid of the device are readable & writable */
    SUBDEV_CID_PERMS_RT      = SUBDEV_CID_PERMS_READ | SUBDEV_CID_PERMS_TRIGGER,  /**< The subdev_cid of the device are readable & triggered */
    SUBDEV_CID_PERMS_WT      = SUBDEV_CID_PERMS_WRITE | SUBDEV_CID_PERMS_TRIGGER, /**< The subdev_cid of the device are writable & triggered */
    SUBDEV_CID_PERMS_RWT     = SUBDEV_CID_PERMS_RW | SUBDEV_CID_PERMS_TRIGGER,    /**< The subdev_cid of the device are readable & writable & triggered */
} subdev_cid_perms_t;

/**
 * @brief Format for the subdev_cid
 */
typedef enum {
    SUBDEV_CID_FORMAT_NONE,   /**< Invalid format */
    SUBDEV_CID_FORMAT_U8,
    SUBDEV_CID_FORMAT_I8,
    SUBDEV_CID_FORMAT_U16,
    SUBDEV_CID_FORMAT_I16,
    SUBDEV_CID_FORMAT_U32,
    SUBDEV_CID_FORMAT_I32,
    SUBDEV_CID_FORMAT_INT,    /**< subdev_cid is a number format */
    SUBDEV_CID_FORMAT_FLOAT, /**< subdev_cid is a double format */
    SUBDEV_CID_FORMAT_STRING, /**< subdev_cid is a string format */
    SUBDEV_CID_FORMAT_ARRAY,  /**< subdev_cid is an array format */
} subdev_cid_format_t;

typedef enum {
    SUBDEV_PROTOCOL_NONE = 0,
	SUBDEV_PROTOCOL_DLT645_07,
	SUBDEV_PROTOCOL_DLT645_97,
	SUBDEV_PROTOCOL_CJT188_04,
	SUBDEV_PROTOCOL_MODBUS_RTU,
	SUBDEV_PROTOCOL_MODBUS_ASCII,
	SUBDEV_PROTOCOL_MODBUS_TCP,
	SUBDEV_PROTOCOL_MODBUS_UDP,
}subdev_protocol_t;

typedef union {
    char *value_string;  /**< The item's string */
	int16_t value_i16;
	uint16_t value_u16;
	int32_t value_i32;
	uint32_t value_u32;
    float value_float; /**< The item's number*/
} cid_value_t;

typedef struct {
	char name[32];
	char cid[32];
	float f;
	char type[8];
	cid_value_t value;
	time_t update_time;
	time_t report_time;
	uint16_t min_inr;
	uint16_t max_inr;
	float change_val;
	uint8_t error;
}subdev_cid_t;

typedef struct {
    uint8_t port_index;
	subdev_protocol_t protocol;
	union {
		/* data */
		struct 
		{
			int8_t uart_num;
		}serial;
		struct 
		{
			int slave_port;
			int slave_num;
			char **slave_ip;
		}modbus_tcp;
		
	}info_union;
	int poll_interval;
	void *port_data;
	uint16_t cids_num;
	subdev_cid_t *cids;

}subdev_port_t;

void mlink_subdev_load_form_flash(void);

/**
 * @brief mlink_subdev_handle_init
 * @return
 */
int mlink_subdev_handle_init(void);

/**
 * @brief mlink_add_subdev
 * @param config 子设备配置
 * @return 子设备句柄
 */
subdev_port_t *mlink_add_subdev(subdev_port_t *new_subdev);

/**
 * @brief 获取子设备句柄
 * @param index 子设备索引
 * @return 子设备句柄
*/
subdev_port_t *mlink_get_subdev_handle_by_index(uint8_t index);

/**
 * @brief 生成子设备CID
 * @param cid 子设备cid名称
 * @param f 子设备cid值
 * @param type 子设备cid类型
 * @param update_time 子设备cid更新时间
 * @param report_time 子设备cid上报时间
 * @param max_inr 子设备cid最大电流值
 * @param change_val 子设备cid变化值
 * @return MDF_OK on success, MDF_FAIL on failure.
*/
mdf_err_t mlink_subdev_cid_init(subdev_cid_t *cid_handle, const char *cid, float f, const char *type, uint16_t max_inr, float change_val, char *name);

/**
 * @brief 添加子设备cid
 * @param subdev 子设备句柄
 * @param cid 子设备cid
 * @return MDF_OK on success, MDF_FAIL on failure.
*/
mdf_err_t mlink_add_subdev_cid(subdev_port_t *subdev, subdev_cid_t *cid);

/**
 * @brief 获取子设备cid的句柄
 * @param subdev 子设备句柄
 * @param cid 子设备cid名称
 * @param index [out] 子设备cid索引
 * @return 子设备cid句柄
 */
subdev_cid_t *mlink_get_subdev_cid_handle_by_name(subdev_port_t *subdev, char *cid, int *index);

/**
 * @brief 获取子设备cid的句柄
 * @param subdev 子设备句柄
 * @param cid 子设备cid索引
 * @return 子设备cid句柄
 */
subdev_cid_t *mlink_get_subdev_cid_handle_by_index(subdev_port_t *subdev, uint16_t index);


/**
 * @brief 设置子设备cid的值
 * 
 * @param subdev 子设备句柄
 * @param cid 子设备cid名称
 * @param value 子设备cid值
 * @return int 0:成功，其他:失败
*/
int mlink_subdev_set_cache_value(subdev_cid_t *cid_handle, void *value);
/**
 * @brief 获取子设备cid的值
 * 
 * @param subdev 子设备句柄
 * @param cid 子设备cid名称
 * @param value 子设备cid值
 * @return int 0:成功，其他:失败
 */
int mlink_subdev_get_cache_value(subdev_cid_t *cid_handle, void *value);

int mlink_subdev_compare_change_value(subdev_cid_t *cid_handle, void *value);
int mlink_subdev_check_max_inr(subdev_cid_t *cid_handle, time_t now);

int subdev_json_pack_value(char **json_str, char *val_type, cid_value_t *val);
/**
 * @brief 解析value值json字符串
 * @param json_str 子设备json字符串
 * @param val_type 子设备value类型
 * @param val 子设备value值
 */
int subdev_json_parse_value(char *json_str, char *val_type, cid_value_t *val);

#ifdef __cplusplus
}
#endif /**< _cplusplus */

#endif /**< __SUB_DEVICE_H__ */
